﻿#region Header

/*
Remote views based on linq
By

Pascal Hauser 
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

and

Raphael Gfeller
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

*/

#endregion

#region Usings

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Linq;
using System.ServiceModel;
using System.Threading;
using InterLinq;
using InterLinq.Objects;
using InterLinq.Sebarf;
using InterLinq.Test.DH.SQL;
using Sebarf.Configuration;
using Sebarf.Core;
using Sebarf.Diagnostics.Interfaces;
using Sebarf.ProcessChains;
using Sebarf.Server;
using Sebarf.Services.Impl;

#endregion

namespace Prototyp1.TestServer {
	/// <summary>
	/// offers the possibility to control the server remotly
	/// </summary>
	public class InterLinqServerRemotControl : MarshalByRefObject {
		#region Public Methods

		/// <summary>
		/// starts the server based on the given data
		/// </summary>
		/// <param name="data"></param>
		/// <returns></returns>
		public string Start(Dictionary<Type, IList> data) {
			try {
				var handler = new ObjectQueryHandler(new ObjectBasedSource(data));
				IServer server = WcfBasedServer.Create(delegate {
					var locator = new ServiceRegistrationLocatorService();
					locator.RegisterService(new ProcessChainManagerService());
					RequestHandlerEngine toReturn = RequestHandlerEngine.Create(locator,
																				 RequestHandlerLoader
																					.Load(
																					"RequestHandler_Server.xaml"));
					locator.GetRegisteredService<IAddRequestHandlerService>().
						AddAddionalHandler(new ExecuteLinqQueryRequestHandler { QueryHandler = handler });
					return toReturn;
				});
				server.Start();

				Logger.WriteInformation("Object based server has been started");
			}
			catch (Exception ex) {
				return ex.Message + "\t" + ex.StackTrace;
			}
			return "DONE";
		}

		/// <summary>
		/// starts the server, data are retrieved from a sql server
		/// </summary>
		/// <param name="cnn">conn to the sql server</param>
		/// <param name="publishServerName">string.Format("net.tcp://{0}:{1}/{2}", publishServerName, publishPort,publishApplicationName)</param>
		/// <param name="publishPort">string.Format("net.tcp://{0}:{1}/{2}", publishServerName, publishPort,publishApplicationName)</param>
		/// <param name="publishApplicationName">string.Format("net.tcp://{0}:{1}/{2}", publishServerName, publishPort,publishApplicationName)</param>
		/// <returns></returns>
		public string Start(string cnn, string publishServerName, string publishPort, string publishApplicationName) {
			try {
				const int datasourcetype = 0;

				IQueryHandler handler = null;
				DataContext datasource = null;
				switch (datasourcetype) {
					case 0:
						datasource = new Interlinq(cnn);
						handler = new LinqToSQLQueryHandler(datasource);
						//var serverQuery = new ServerQueryWcfHandler(serverClientSQL) { NetTcpBinding = GetNetTcpBinding(), ServiceUri = string.Format("net.tcp://{0}:{1}/{2}", publishServerName, publishPort, publishApplicationName) };
						//server.Start(serverQuery, new IServerProfileImpl[] { Profiles.Server.ServerProfiles.GetCacheBasedProfile(), Profiles.Server.ServerProfiles.GetCacheLessProfile(), Profiles.Server.ServerProfiles.GetLazyLoadingCacheBasedProfile(), Profiles.Server.ServerProfiles.GetSecurityBasedCacheBasedLazyLoadProfile() });
						break;
				}

				IServer server = WcfBasedServer.Create(delegate {
					var locator = new ServiceRegistrationLocatorService();
					locator.RegisterService(new ProcessChainManagerService());
					RequestHandlerEngine toReturn = RequestHandlerEngine.Create(locator,
																				 RequestHandlerLoader
																					.Load(
																					"RequestHandler_Server.xaml"));
					locator.GetRegisteredService<IAddRequestHandlerService>().
						AddAddionalHandler(new ExecuteLinqQueryRequestHandler { QueryHandler = handler });
					return toReturn;
				});
				server.Start();

				Logger.WriteInformation("Connected to: " + cnn);

				Logger.WriteInformation("Server was started.\nPress any key to exit.");
			}
			catch (Exception ex) {
				return ex.Message;
			}
			return "DONE";
		}

		/// <summary>
		/// <see cref="Start">(string cnn,string publishServerName,string publishPort,string publishApplicationName)</see>
		/// Calls Start(string cnn, string cnn,string publishServerName,string publishPort,string publishApplicationName) with "localhost", "7890", "InterLinqService"
		/// </summary>
		/// <param name="cnn"></param>
		/// <returns></returns>
		public string Start(string cnn) {
			return Start(cnn, "localhost", "7890", "InterLinqService");
		}

		#endregion

		#region Private Methods

		private static NetTcpBinding GetNetTcpBinding() {
			var netTcpBinding = new NetTcpBinding();

			netTcpBinding.Security.Mode = SecurityMode.None;

			netTcpBinding.MaxBufferSize = int.MaxValue;
			netTcpBinding.MaxReceivedMessageSize = int.MaxValue;
			netTcpBinding.ReaderQuotas.MaxArrayLength = int.MaxValue;

			netTcpBinding.OpenTimeout = TimeSpan.MaxValue;
			netTcpBinding.CloseTimeout = TimeSpan.MaxValue;
			netTcpBinding.SendTimeout = TimeSpan.MaxValue;

			return netTcpBinding;
		}

		#endregion

		#region Private classes

		/// <summary>
		/// Helper class for the object query handler
		/// </summary>
		private class ObjectBasedSource : IObjectSource {
			#region Public Methods

			public ObjectBasedSource(Dictionary<Type, IList> data) {
				m_data = data;
			}

			#endregion

			#region Private Fields

			private readonly Dictionary<Type, IList> m_data = new Dictionary<Type, IList>();

			#endregion

			private readonly ReaderWriterLock _lock = new ReaderWriterLock();

			#region IObjectSource Members

			public ReaderWriterLock Lock {
				get { return _lock; }
			}

			public IEnumerable<T> GetObjects<T>() {
				return (IEnumerable<T>)m_data[typeof(T)];
			}

			public void AddObject<T>(T obj) {
				try {
					Lock.AcquireWriterLock(-1);
					m_data[typeof(T)].Add(obj);
				}
				finally {
					Lock.ReleaseWriterLock();
				}
			}

			public void AddObject(Type t, object obj) {
				try {
					Lock.AcquireWriterLock(-1);
					m_data[t].Add(obj);
				}
				finally {
					Lock.ReleaseWriterLock();
				}
			}

			public void DeleteObject(Type t, object obj) {
				try {
					Lock.AcquireWriterLock(-1);
					m_data[t].Remove(obj);
				}
				finally {
					Lock.ReleaseWriterLock();
				}
			}

			#endregion
		}

		#endregion
	}
}